import time
from multiprocessing import Queue

import PySide6
from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton, QFrame, QLineEdit, QFormLayout, QComboBox, \
    QGridLayout, QMenu, QSizePolicy, QDockWidget, QScrollArea, QMessageBox, QHBoxLayout, QToolBar, QMenuBar, \
    QAbstractButton, QStyledItemDelegate, QTabWidget, QInputDialog
import json

from PySide6 import QtGui
from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton, QFrame, QLineEdit, QFormLayout, QComboBox, \
    QGridLayout, QMenu, QSizePolicy, QDockWidget, QScrollArea
from PySide6.QtCore import Qt, QPoint, QRect, QSize, QEvent, QThread, QTimer
from PySide6.QtGui import QCursor, QPaintEvent, QAction, QPainter, QPen
from PySide6.QtCore import Signal

from extend_ui.dialog_class import Dialog_Edit


class My_ScrollArea(QScrollArea):
    """
        继承QScrollArea类
        重载sizeHint函数，用来改变初始化时Dock的大小
    """

    def __init__(self, parent=None):
        super(My_ScrollArea, self).__init__(parent)
        self.width = 1440
        self.height = 500

    def sizeHint(self) -> PySide6.QtCore.QSize:
        return QSize(self.width, self.height)

    def wheelEvent(self, event):
        if event.modifiers() == Qt.ShiftModifier:
            # 获取滚动条当前位置
            current_pos = self.horizontalScrollBar().value()

            # 根据滚轮滚动方向进行横向滚动
            if event.angleDelta().y() > 0:
                # 向左滚动
                self.horizontalScrollBar().setValue(current_pos - 50)
            else:
                # 向右滚动
                self.horizontalScrollBar().setValue(current_pos + 50)
        else:
            # 默认情况下，执行普通的垂直滚动
            super().wheelEvent(event)

    def setSize(self, size):
        self.width = size[0]
        self.height = size[1]
        self.sizeHint()


class Resize_Thread(QThread):
    resize_signal = Signal()
    """ 
    新办法实现给dock设置size 
    原理是先设置相同大小的最大尺寸和最小尺寸相当于setFixedSize()
    然后通过线程的方式在通知主线程将最大值和最小值改回去，
    用线程的目的是为了不让两件事在同一个循环周期内进行，否则效果不会生效
    """

    def run(self):
        time.sleep(0.001)
        self.resize_signal.emit()


class Dock_Console(QDockWidget):
    """
        Dock形式的控制台
        1.继承QDockWidget类
        2.父类是主窗口 《重要》 部分关键变量要从父类获取
        3.创建了一个空的QWidget (self.widget) 在QDockWidget上,自定义的可拖拽组件添加在该QWidget上
        4.注意父类的关系是：
            MainWindow
            Dock_Console(QDockWidget)
            scroll_area(QScrollArea)
            tabwidget(QTabWidget)
            content_widget(QWidget)
            widget(DraggableWidget)
    """

    def __init__(self,
                 parent,
                 config=None,
                 title_bar_widgets=[],
                 signal_online_stateChanged=Signal(),
                 queue_logging=Queue(),
                 grid_size=None):
        super().__init__(parent)
        self.signal_table_info = parent.signal_table_info
        self.signal_operat = parent.signal_operat
        self.signal_online_stateChanged = signal_online_stateChanged
        self.table_info = parent.table_info
        self.queue_logging = queue_logging

        # 创建ScrollLabel的定时器
        self.timer_scrollLabel = QTimer()
        self.timer_scrollLabel.start(100)

        # 添加dock
        parent.addDockWidget(Qt.BottomDockWidgetArea, self)
        self.setWindowTitle('控制台')
        # 添加scroll area 用于自动设置滚动条
        self.scroll_area = My_ScrollArea(self)
        self.setWidget(self.scroll_area)
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scroll_area.setStyleSheet(
            "QScrollBar:vertical {width: 15px;height: 15px;}")

        # 设置单元格像素
        if grid_size:
            self.grid_size = grid_size
        else:
            self.grid_size = [50, 50]

        # 获取resize的线程
        self.resize_thread = Resize_Thread()
        self.resize_thread.resize_signal.connect(self.setSize_MAX_MINI)
        self.timer_resize = QTimer()
        self.timer_resize.setSingleShot(True)
        self.timer_resize.timeout.connect(self.setSize_MAX_MINI)

        # # 根据参数初始化dock的大小
        # self.scroll_area.width = self.width
        # self.scroll_area.height = self.height
        # self.scroll_area.sizeHint()

        self.config = config
        self.DraggableWidget_Object = DraggableWidget

        self.tabWidget = CustomTabWidget(self.scroll_area,
                                         grid_size=self.grid_size,
                                         config=self.config,
                                         signal_table_info=self.signal_table_info,
                                         signal_online_stateChanged=self.signal_online_stateChanged,
                                         timer_scrollLabel=self.timer_scrollLabel,
                                         table_info=self.table_info,
                                         queue_logging=self.queue_logging,)
        self.scroll_area.setWidget(self.tabWidget)

        if type(self) == Dock_Console:
            self.load_config()
        self.setTitleBarWidget(title_bar_widgets)

        # 判断是否为空的控制台
        if self.tabWidget.draggable_widgets == {'New Tab': {}}:
            self.close()
        else:
            pass

    def setTitleBarWidget(self, title_bar_widgets):
        if title_bar_widgets:
            title_bar = QWidget()
            title_bar.setStyleSheet("background-color: #dadada")
            layout = QGridLayout(title_bar)
            layout.setContentsMargins(0, 0, 0, 0)
            frame = QFrame()
            frame.setContentsMargins(0, 0, 0, 0)
            frame.setFixedWidth(280)
            frame_layout = QHBoxLayout(frame)
            frame_layout.setContentsMargins(0, 0, 0, 0)
            title_bar.title = QLabel(self.windowTitle(), title_bar)
            title_bar.title.setFixedWidth(40)
            # title_bar.title.setStyleSheet('background-color: red')
            tool_bar = QMenuBar(title_bar)
            # tool_bar.setStyleSheet('background-color: blue')

            # tool_bar.setMaximumWidth(600)
            tool_bar.setFixedWidth(1000)
            tool_bar.setNativeMenuBar(False)
            for widget in title_bar_widgets:
                if isinstance(widget, QAction):
                    tool_bar.addAction(widget)
                    tool_bar.addSeparator()
                elif isinstance(widget, QMenu):
                    tool_bar.addMenu(widget)
                    tool_bar.addSeparator()

            # 添加全屏 和 关闭按钮
            button_full = QPushButton('□')
            button_full.setFixedSize(16, 16)
            button_full.clicked.connect(self.float_action_slot)
            button_close = QPushButton('X')
            button_close.setFixedSize(16, 16)
            button_close.clicked.connect(self.close)
            frame_layout.addWidget(title_bar.title)
            frame_layout.addWidget(tool_bar)
            layout.addWidget(frame, 0, 0, 1, 1, Qt.AlignLeft)
            layout.addWidget(button_full, 0, 11, 1, 1)
            layout.addWidget(button_close, 0, 12, 1, 1)
            return super().setTitleBarWidget(title_bar)

    def float_action_slot(self, a):
        if not self.isFloating():
            self.setFloating(True)
        else:
            if not self.isFullScreen():
                self.showFullScreen()
            else:
                self.showNormal()

    # 重载尺寸事件
    def resizeEvent(self, event) -> None:
        # print(type(self), self.scroll_area.size())
        self.tabWidget.resize_widget()

    # 添加控制台控件
    def add_draggableWidget(self, widget_type=2, addr=0, config=None):
        self.tabWidget.add_draggableWidget(widget_type=widget_type, addr=addr, config=config)
        if not self.isVisible():
            self.show()
            self.signal_operat.emit(6, 1, [type(self)])

    # 刷新数据
    def refresh(self, addrs, values):
        self.tabWidget.refresh(addrs, values)

    def load_config(self):
        if self.config is not None:
            try:
                self.scroll_area.setSize(self.config['size'])
            except Exception as e:
                # my_logger.debug('在生成控制台控件时遇到无法识别的唯一编号，跳过了此项的生成!')
                self.queue_logging.put([1, 0, '设置控制台尺寸出错!'])
                # print(1, e)
        self.tabWidget.load_config()

    def get_config(self):
        """
        1. 获取console的size
        2. 获取所有已添加的DraggableWidget的config
        返回{size:[0,0], tab_name:['控制台', 'New Tab] widgets: {'tab_name':[{}{}{}]}
        """
        config_dict = {}
        config_dict['size'] = [self.scroll_area.size().width(), self.scroll_area.size().height()]
        config_dict['curr_tab_name'], config_dict['tab_name'], config_dict['tab_tip_list'], config_dict['widgets'] = self.tabWidget.get_config()
        return config_dict

    def closeEvent(self, event):
        self.signal_operat.emit(6, 0, [type(self)])

    def set_size(self, size):
        # print(size)
        self.setMaximumSize(size[0], size[1])
        self.setMinimumSize(size[0], size[1])
        # self.resize_thread.start()
        self.timer_resize.start(5)

    def setSize_MAX_MINI(self):
        self.setMaximumSize(4096, 2160)
        self.setMinimumSize(10, 10)

    # def change_grid_size(self, grid_size):
    #     for i in range(self.tabWidget.count()):
    #         child_list = self.tabWidget.widget(i).widget.children()
    #         for child in child_list:
    #             if isinstance(child, DraggableWidget):
    #                 print(int(child.geometry().x() / child.grid_size[0])* grid_size[0], int(child.geometry().y() / child.grid_size[1]) * grid_size[1])
    #                 child.move(int(child.geometry().x() / child.grid_size[0]) * grid_size[0], int(child.geometry().y() / child.grid_size[1]) * grid_size[1])



class DraggableWidget(QFrame):
    '''可拖拽移动的自定义组件'''

    def __init__(self,
                 parent=None,
                 grid_size=[1, 1],
                 config=None,
                 signal_table_info=Signal(),
                 delete_self_signal=Signal(),
                 signal_online_stateChanged=Signal(),
                 timer_scrollLabel=Signal(),
                 queue_logging=Queue(),
                 table_info=None,
                 addr=0):
        super().__init__(parent)
        # 设置一个边框阴影表示范围
        self.setFrameShape(QFrame.Box)  # 设置边框形状为 StyledPanel
        self.setLineWidth(2)
        self.setFrameShadow(QFrame.Raised)

        #
        self.signal_table_info = signal_table_info
        self.signal_online_stateChanged = signal_online_stateChanged
        self.delete_self_signal = delete_self_signal
        self.timer_scrollLabel = timer_scrollLabel
        # self.signal_online_stateChanged.connect(self.set_drag_enable)
        self.queue_logging = queue_logging
        # drag enable
        self.drag_enable = True

        # 初始化 变量
        self.drag_start_position = None
        self.original_position = None
        self.config = config
        self.table_info = table_info
        self.addr = addr
        self.resize_flag = False
        self.old_pos = None                     # 全局拖动时保存移动前的地址
        self.selected = False                   # 是否被全局选择了的标志

        # 网格设置
        self.grid_size = grid_size

        # 设置自定义组件
        self.init_widget()
        self.init_pos()

    def init_widget(self):
        """名称+自定义控件初始化"""
        # 控件
        if self.config['widget_type'] == 0:
            widget_object = My_ComboBox
        elif self.config['widget_type'] == 1:
            widget_object = My_LineEdit
        elif self.config['widget_type'] == 2:
            widget_object = My_ButtonGroup
        self.widget = widget_object(self)
        # 名称
        label_text = self.table_info['category_id'][self.addr] + '_' + self.table_info['var_comment'][self.addr]
        Label = ScrollingLabel(parent=self, text=label_text, timer_scrollLabel=self.timer_scrollLabel)
        # 获取提示信息
        tips_text = self.table_info['category_id'][self.addr] + '-' + \
                    self.table_info['type_lv1'][self.addr] + '-' + \
                    self.table_info['type_lv2'][self.addr] + '\n' + \
                    self.table_info['var_comment'][self.addr]
        Label.setToolTip(tips_text)
        Label.setAlignment(Qt.AlignCenter)
        Label.setWordWrap(True)
        Label.setFixedHeight(int(0.45 * self.grid_size[1]))
        # Label.setMaximumWidth(self.grid_size[0])
        """控件布局: 两行,第一行是名称label,第二行是自定义的控件"""
        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.layout.addWidget(Label)
        self.layout.addWidget(self.widget)
        """初始化大小和位置"""

        if self.widget.grid_size_number[0] == 1:
            self.setFixedSize(
                2 * self.grid_size[0] - 2,
                self.widget.grid_size_number[1] * self.grid_size[1] - 2)
        else:
            self.setFixedSize(
                self.widget.grid_size_number[0] * self.grid_size[0] - 2,
                self.widget.grid_size_number[1] * self.grid_size[1] - 2)

        """ 设置背景颜色 """
        # 默认颜色
        if self.table_info['isWritable'][self.addr] == 1:
            self.default_StyleSheet = """
            """
        else:
            self.default_StyleSheet = """
                QFrame{
                    background-color: rgb(153,157,156);
                }
            """

        # 创建选中的样式
        self.select_StyleSheet = """
            QFrame{
                background-color: lightblue;
            }
        """
        self.setStyleSheet(self.default_StyleSheet)

    def init_pos(self):
        # 初始化位置
        if 'pos' not in self.config.keys():  # config中无位置信息则自动设置位置
            x, y = 0, 0
            widget_rect = self.parent().rect()
            while self.IsIntersects(x, y):
                x = x + self.grid_size[0]
                if x + self.width() > widget_rect.width():  # 超出右边界
                    x, y = 0, y + self.grid_size[1]
                if y + self.height() > widget_rect.height():  # 超出父类范围
                    x, y = 0, 0
                    # self.delete_myself()
                    QMessageBox.warning(self, '警告', '没有多余空间了!',
                                        QMessageBox.Yes)
                    self.delete_self_signal.emit(self)
                    # QMessageBox.warning(self, '警告', '没有多余空间了!',
                    #                     QMessageBox.Yes)
                    print('没有空间了')  # 换成qmessage的warning
                    break
            self.config['pos'] = [int(x / self.grid_size[0]), int(y / self.grid_size[1])]
        else:
            # x, y = self.config['pos']
            # self.config['pos'] = [int(x / self.grid_size[0]), int(y / self.grid_size[1])]
            x, y = self.config['pos'][0] * self.grid_size[0], self.config['pos'][1] * self.grid_size[1]
        self.move(QPoint(x, y))
        # 不加这个show不显示控件，因为不是自动追加的layout事件
        self.show()

    def set_drag_enable(self, flag):
        self.drag_enable = not flag

    def delete_myself(self):
        # 关闭窗口并释放内存
        # self.destroy()
        # # 从父类中删除
        # self.setParent(None)
        self.deleteLater()

    """拖拽移动的相关函数"""

    # 判断移动到 (x,y)后是否和其他控件重合了
    def IsIntersects(self, x, y):
        rect = QRect(x, y, self.width(), self.height())
        for child in self.parent().children():
            if isinstance(child, type(self)) and child is not self:
                if rect.intersects(child.geometry()):
                    return True
        return False

    # 重写mousePressEvent 记录左键点击拖动的起始位置
    def mousePressEvent(self, event):
        if self.selected:
            pass
        elif event.button() == Qt.LeftButton and self.drag_enable:
            self.drag_start_position = event.pos()
            # 坐标原点在父类widget的左上角,self.pos()是自己图标左上角在父类widget坐标系的坐标
            self.original_position = self.pos()
            return
        else:
            pass
        super(DraggableWidget, self).mousePressEvent(event)

    # 重写mouseMoveEvent 实现左键点击拖动后控件移动
    def mouseMoveEvent(self, event):
        if self.selected:
            pass
        elif event.buttons() == Qt.LeftButton and self.drag_enable and self.drag_start_position is not None:
            # 获取 QWidget 的矩形范围
            self.setStyleSheet(self.select_StyleSheet)
            widget_rect = self.parent().rect()

            old_pos = self.pos()

            # 获取鼠标移动的距离
            drag_distance = event.pos() - self.drag_start_position
            new_pos = self.pos() + drag_distance

            # 将位置限制在网格上(左上角端点吸附在网格上)
            x = int(round(new_pos.x() / self.grid_size[0])) * self.grid_size[0]
            y = int(round(new_pos.y() / self.grid_size[1])) * self.grid_size[1]


            # # 将新位置限制在 QWidget 的范围内
            # 上
            while (y < 0):
                y = y + self.grid_size[1]
            # 下
            while (y + self.height() > widget_rect.height()):
                y = y - self.grid_size[1]
            # 左
            while (x < 0):
                x = x + self.grid_size[0]
            # 右
            while (x + self.width() > widget_rect.width()):
                x = x - self.grid_size[0]

            self.move(QPoint(x, y))
        super(DraggableWidget, self).mouseMoveEvent(event)

    # 重写mouseRelaseEvent
    # 鼠标拖动松开后判断是否有重合，并记录widget的最新位置
    def mouseReleaseEvent(self, event):
        if self.selected:
            pass
        elif self.drag_enable:
            if self.IsIntersects(self.pos().x(), self.pos().y()):  # 重合就回到原始位置
                self.move(self.original_position)
            # 记录最新位置
            # self.config['pos'] = [self.pos().x(), self.pos().y()]
            self.config['pos'] = [int(self.pos().x() / self.grid_size[0]), int(self.pos().y() / self.grid_size[1])]
        super(DraggableWidget, self).mouseReleaseEvent(event)

    def all_press_event(self):
        """ 当有全局选中时，为每一个选中的控件保存初始位置记录 """
        self.old_pos = self.pos()

    def all_move_event(self, drag_distance):
        """ 全局选中控件的移动 """
        widget_rect = self.parent().rect()
        # 获取新位置
        new_pos = self.old_pos + drag_distance

        # 将位置限制在网格上(左上角端点吸附在网格上)
        x = int(round(new_pos.x() / self.grid_size[0])) * self.grid_size[0]
        y = int(round(new_pos.y() / self.grid_size[1])) * self.grid_size[1]

        # 将新位置限制在 QWidget 的范围内
        # 上
        while (y < 0):
            y = y + self.grid_size[1]
        # 下
        while (y + self.height() > widget_rect.height()):
            y = y - self.grid_size[1]
        # 左
        while (x < 0):
            x = x + self.grid_size[0]
        # 右
        while (x + self.width() > widget_rect.width()):
            x = x - self.grid_size[0]
        self.move(QPoint(x, y))

    def all_release_event(self):
        """ 全局移动结束 判断是否造成了重叠 """
        if self.IsIntersects(self.pos().x(), self.pos().y()):  # 重合就回到原始位置
            return True
        else:
            return False

    def all_default_event(self):
        """ 如果全局移动结束 有重叠的控件 就恢复 老样子 """
        self.move(self.old_pos)
        # 记录最新位置
        self.config['pos'] = [int(self.pos().x() / self.grid_size[0]), int(self.pos().y() / self.grid_size[1])]

    def all_save_event(self):
        self.config['pos'] = [int(self.pos().x() / self.grid_size[0]), int(self.pos().y() / self.grid_size[1])]


class My_LineEdit(QLineEdit):
    """自定义输入控件"""

    def __init__(self, parent):
        super().__init__(parent)
        self.config = parent.config
        self.grid_size = parent.grid_size
        self.signal_table_info = parent.signal_table_info
        self.var_addr = parent.addr
        self.table_info = parent.table_info
        self.queue_logging = parent.queue_logging
        self.init_layout()

        # 根据 config['name']和table_info查询具体信息
        self.setReadOnly(True)
        self.setFocusPolicy(Qt.NoFocus)

    def mouseDoubleClickEvent(self, a0: QtGui.QMouseEvent) -> None:
        if self.table_info['isWritable'][self.var_addr] == 1:
            dialog_edit = Dialog_Edit(self)
            dialog_edit.display(self.var_addr)
        else:
            pass

    def init_layout(self):
        # LineEdit占据2x1个网格
        self.setObjectName('self')
        # QFrame
        # {
        #     background - color: rgb(153, 157, 156);
        # }
        line_edit_stylesheet = """
            QLineEdit#self {
                border: 2px solid gray;
                background-color: rgb(153, 157, 156);
                color: black;
            }
        """
        self.grid_size_number = (2, 1)
        if self.table_info['isWritable'][self.var_addr] == 1:
            self.setEnabled(True)
        else:
            self.setEnabled(False)
            self.setStyleSheet(line_edit_stylesheet)
        self.setAlignment(Qt.AlignCenter)
        # 禁用右键菜单
        self.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu)
        if self.table_info['var_type'][self.var_addr] in ['int', '1']:
            self.setText(
                str(int(self.table_info['var_current'][self.var_addr])) +
                self.table_info['var_unit'][self.var_addr])
        elif self.table_info['var_type'][self.var_addr] in ['bit', '5']:
            self.setText(str(hex(int(self.table_info['var_current'][self.var_addr]))))
        else:
            if 0.0 < abs(self.table_info['var_current'][self.var_addr]) < 0.01:
                self.setText(
                    '{:.2e}'.format(self.table_info['var_current'][self.var_addr]) +
                    self.table_info['var_unit'][self.var_addr])
            elif self.table_info['var_current'][self.var_addr] > 100000:
                self.setText(
                    '{:.4e}'.format(self.table_info['var_current'][self.var_addr]) +
                    self.table_info['var_unit'][self.var_addr])
            else:
                if self.table_info['var_decimal'][self.var_addr]:
                    self.setText(
                        ('%.' + self.table_info['var_decimal'][self.var_addr] +
                         'f' % self.table_info['var_current'][self.var_addr]) +
                        self.table_info['var_unit'][self.var_addr])
                else:
                    self.setText(('%.2f' %
                                  self.table_info['var_current'][self.var_addr]) +
                                 self.table_info['var_unit'][self.var_addr])
        # self.setText(str(self.table_info['当前值'][self.var_addr]) + self.table_info['单位'][self.var_addr])

    def refresh(self, value):
        if self.table_info['var_type'][self.var_addr] in ['int', '1']:
            self.setText(
                str(int(value)) +
                self.table_info['var_unit'][self.var_addr])
        elif self.table_info['var_type'][self.var_addr] in ['bit', '5']:
            self.setText(str(hex(int(value))))
        else:
            if 0.0 < abs(value) < 0.01:
                self.setText('{:.2e}'.format(value) +
                             self.table_info['var_unit'][self.var_addr])
            elif value > 100000:
                self.setText('{:.4e}'.format(value) +
                             self.table_info['var_unit'][self.var_addr])
            else:
                if self.table_info['var_decimal'][self.var_addr]:
                    self.setText((
                                         '%.' + self.table_info['var_decimal'][self.var_addr] +
                                         'f' % value) +
                                 self.table_info['var_unit'][self.var_addr])
                else:
                    self.setText(('%.2f' % value) +
                                 self.table_info['var_unit'][self.var_addr])


class My_ComboBox(QComboBox):
    """自定义选择控件"""

    def __init__(self, parent):
        super().__init__(parent)
        self.config = parent.config
        self.grid_size = parent.grid_size
        self.signal_table_info = parent.signal_table_info
        self.queue_logging = parent.queue_logging
        self.var_addr = parent.addr
        ''' 根据 config['name']和table_info查询具体信息 '''
        table_info = parent.table_info

        # 获取按钮操作权限
        self.combox_operate_type = table_info['isWritable'][self.var_addr]

        self.combox_name_list = list(
            table_info['action_define'][self.var_addr].values())
        self.index_list = list(
            map(int, table_info['action_define'][self.var_addr].keys()))
        self.addItems(self.combox_name_list)
        # print(table_info['action_define'][self.var_addr].keys())
        self.setCurrentIndex(
            list(table_info['action_define'][self.var_addr].keys()).index(
                str(int(table_info['var_current'][self.var_addr]))))

        # 修改combox触发的动作
        self.currentIndexChanged.connect(self.combox_changed)

        self.init_layout()

    # 选择条目触发的信号
    def combox_changed(self):
        value = self.index_list[self.currentIndex()]
        self.signal_table_info.emit(0, [self.var_addr], [value])

    # # 重写滚动事件，屏蔽滚动选值功能
    # def wheelEvent(self, event: QtGui.QWheelEvent):
    #     super().wheelEvent(event)

    def event(self, event):
        if event.type() == QEvent.Wheel:
            return False
        return super().event(event)

    # 刷新combobox选项
    def refresh(self, value):
        self.setCurrentIndex(self.index_list.index(value))

    def init_layout(self):
        # 设置宽度的尺寸策略为扩展
        self.setSizePolicy(QSizePolicy.Expanding, self.sizePolicy().verticalPolicy())
        # 将每一个项都设置一个提示
        for index in range(self.count()):
            self.setItemData(index, self.combox_name_list[index], Qt.ToolTipRole)
        # 判断下拉操作权限
        if self.combox_operate_type == 1:
            self.setEnabled(True)
        else:
            self.setEnabled(False)
        # ComboBox占据2x1个网格
        self.grid_size_number = (2, 1)
        self.setFocusPolicy(Qt.NoFocus)


class My_ButtonGroup(QFrame):
    """自定义按钮控件"""

    def __init__(self, parent):
        super().__init__(parent)
        self.config = parent.config
        self.grid_size = parent.grid_size
        self.signal_table_info = parent.signal_table_info
        self.timer_scrollLabel = parent.timer_scrollLabel
        self.var_addr = parent.addr
        # self.setStyleSheet('background-color: red')

        # 根据 config['name']和table_info查询具体信息
        table_info = parent.table_info
        self.button_name_list = list(
            table_info['action_define'][self.var_addr].values())
        self.index_list = list(
            map(int, table_info['action_define'][self.var_addr].keys()))
        # print(self.button_name_list, self.var_addr)
        if self.button_name_list[0] in ['off', 'no', '禁止']:
            del self.button_name_list[0]
            del self.index_list[0]

        # 获取提示的前缀
        self.tip_text_pre = table_info['category_id'][self.var_addr] + '-' + \
                            table_info['type_lv1'][self.var_addr] + '-' + \
                            table_info['type_lv2'][self.var_addr] + '\n' + \
                            table_info['var_comment'][self.var_addr] + '-'

        # 获取按钮操作权限, 设置按钮组背景颜色
        self.button_operate_type = table_info['isWritable'][self.var_addr]
        # if self.button_operate_type == '1':
        #     parent.setStyleSheet('background-color:white')
        # else:
        #     self.setStyleSheet('background-color: rgb(153,157,156)')

        # button的类型 0不互斥， 1互斥
        self.button_type = table_info['var_type'][self.var_addr]

        self.init_layout()

        for button in self.button_list:
            button.clicked.connect(self.button_clicked)

    # 点击按钮引发的事件
    def button_clicked(self, a):
        tmp = 0
        if self.button_type in ['bit', '5']:
            for i, button in enumerate(self.button_list):
                if button.isChecked():
                    # button.checkStateSet(not button.isChecked())
                    tmp = tmp + 2 ** self.index_list[i]
                    button.setStyleSheet(self.green_stylesheet)
                else:
                    button.setStyleSheet(self.red_stylesheet)
        elif self.button_type in ['enum', '3']:
            if len(self.button_list) == 1:
                button = self.sender()
                if button.isChecked():
                    tmp = self.index_list[0]
                    button.setStyleSheet(self.green_stylesheet)
                else:
                    button.setStyleSheet(self.red_stylesheet)
            else:
                for i, button in enumerate(self.button_list):
                    if button == self.sender():
                        tmp = self.index_list[i]
                        button.setStyleSheet(self.green_stylesheet)
                    else:
                        button.setStyleSheet(self.red_stylesheet)
        else:
            pass

        self.signal_table_info.emit(0, [self.var_addr], [tmp])

    # 上层引发的刷新数据
    def refresh(self, value):
        if self.button_type in ['bit', '5']:
            for j, button in enumerate(self.button_list):
                if ((int(value) >> self.index_list[j]) & 1) == 1:
                    button.setChecked(True)
                    button.setStyleSheet(self.green_stylesheet)
                else:
                    button.setChecked(False)
                    button.setStyleSheet(self.red_stylesheet)
        elif self.button_type in ['enum', '3']:
            for j, button in enumerate(self.button_list):
                if self.index_list[j] == value:
                    button.setChecked(True)
                    button.setStyleSheet(self.green_stylesheet)
                else:
                    button.setChecked(False)
                    button.setStyleSheet(self.red_stylesheet)
        else:
            pass

    def init_layout(self):
        # ButtonGroup占据 nx2个网格（n为button数量）
        self.layout = QGridLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.button_list = []

        label_fixed_height = int(self.grid_size[1] * 0.3)  # label大小为x轴grid的30%
        button_fixed_size = int(self.grid_size[1] * 0.8)  # 按钮的大小为y轴grid的80%
        self.button_radius = int(button_fixed_size / 2)


        # 创建变量
        self.red_stylesheet = '''
        QPushButton {
            background-color: rgb(200, 0, 0);
            border-radius: ''' + str(self.button_radius) + '''px;
            border: 2px groove gray;
            border-style: outset;
        }
        QToolTip {
            background-color: #FF0000;
            color: black;
        }
        '''

        self.green_stylesheet = '''
        QPushButton {
            background-color: rgb(0, 200, 0);
            border-radius: ''' + str(self.button_radius) + '''px;
            border: 2px groove gray;
            border-style: outset;
        }
        QToolTip {
            background-color: #FF0000;
            color: black;
        }
        '''

        for i, button_text in enumerate(self.button_name_list):

            button_label = ScrollingLabel(text=button_text, timer_scrollLabel=self.timer_scrollLabel)
            # if self.button_operate_type == 1:
            #     button_label.setStyleSheet('background-color:white')
            # else:
            #     button_label.setStyleSheet(
            #         'background-color: rgb(153,157,156)')
            button_label.setToolTip(self.tip_text_pre + button_text)
            button_label.setAlignment(Qt.AlignCenter)
            button_label.setFixedHeight(label_fixed_height)
            button_label.setFixedWidth(40)
            button = My_Button()
            button.setFocusPolicy(Qt.NoFocus)
            button.setCheckable(True)
            button.setToolTip(self.tip_text_pre + button_text)
            # 判断按钮是否可以操作('1'可读写， else只读)
            if self.button_operate_type == 1:
                button.setEnabled(True)
            else:
                button.setEnabled(False)
            button.setFixedSize(button_fixed_size, button_fixed_size)



            if self.button_type in ['enum', '3'] and self.index_list[i] == 0:
                button.setStyleSheet(self.green_stylesheet)
            else:
                button.setStyleSheet(self.red_stylesheet)
            self.button_list.append(button)

            self.layout.addWidget(button_label, 0, i, 1, 1)
            self.layout.addWidget(button, 1, i, 1, 1)

        n = len(self.button_list)

        # 将单个按钮扩大二倍
        if n == 1:
            n = 2
        self.grid_size_number = (n, 2)
        self.setFixedWidth(int(n * self.grid_size[0]) - 10)
        self.setFixedHeight(int(1.35 * self.grid_size[1]))


class My_Button(QPushButton):
    def event(self, event):
        if event.type() == QEvent.Wheel:
            return False
        return super().event(event)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Space:
            # 屏蔽 Tab 键盘事件
            event.accept()
            return

        # 其他键盘事件的处理
        super().keyPressEvent(event)


class My_Widget(QWidget):
    """
    重新定义中心控件，增加拖动选中的功能
    """
    def __init__(self, parent, signal_online_stateChanged):
        super(My_Widget, self).__init__(parent)
        # 获取变量
        self.signal_online_stateChanged = signal_online_stateChanged
        # self.signal_online_stateChanged.connect(self.set_drag_enable)
        # self.setMouseTracking(True)
        # 创建变量
        self.selecting = False                              # 是否启用了选择
        self.moveing = False                                # 是否启用了移动
        self.selection_rect = None                          # 选择框大小
        self.drag_start_position = None                     # 拖动的起始位置
        self.selection_start_pos = QPoint()                 # 选择的起始位置
        self.selected_frames = []                           # 选中的控件列表
        self.drag_enable = True                             # 是否可选中的标志
        self.setFocusPolicy(Qt.NoFocus)

    def set_drag_enable(self, flag):
        self.drag_enable = not flag

    def mousePressEvent(self, event):
        # 判断是否是移动
        if not self.drag_enable:
            return
        if event.button() == Qt.LeftButton and self.selected_frames:
            # 判断移动的起始点在不在选择的控件上
            for frame in self.selected_frames:
                if frame.geometry().contains(event.pos()):
                    self.moveing = True
                    break
            # 在的话就准备移动
            if self.moveing:
                self.moveing = True
                self.drag_start_position = event.pos()
                # print('yuan', self.drag_start_position.x(), self.drag_start_position.y())
                for frame in self.selected_frames:
                    frame.all_press_event()
            # 不在的话就重新选择
            else:
                list_frame = self.children()
                for frame in list_frame:
                    if isinstance(frame, DraggableWidget):
                        frame.setStyleSheet(frame.default_StyleSheet)
                        frame.selected = False
                self.selected_frames = []
                self.selecting = True
                self.selection_start_pos = event.pos()
                self.selection_rect = QRect(self.selection_start_pos, QSize())
        # 判断是否要准备选择
        elif event.button() == Qt.LeftButton and not self.selecting:
            self.selecting = True
            self.selection_start_pos = event.pos()
            self.selection_rect = QRect(self.selection_start_pos, QSize())

    def mouseMoveEvent(self, event):
        if not self.drag_enable:
            return
        # 移动
        if self.selected_frames and self.moveing:
            drag_distance = event.pos() - self.drag_start_position
            for frame in self.selected_frames:
                frame.all_move_event(drag_distance)
        # 选择
        elif self.selecting:
            self.selection_rect.setBottomRight(event.pos())
            self.update()

    def mouseReleaseEvent(self, event):
        if not self.drag_enable:
            return
        # 移动结束
        if event.button() == Qt.LeftButton and self.moveing:
            self.moveing = False
            list_frame = self.children()
            # 判断是否重叠
            err = False
            for frame in self.selected_frames:
                if isinstance(frame, DraggableWidget):
                    if frame.all_release_event():
                        err = True
                        break
            # 重叠的话就恢复老样子
            if err:
                for frame in self.selected_frames:
                    if isinstance(frame, DraggableWidget):
                        frame.all_default_event()
            # 恢复默认样式 清空子控件的选择标志
            for frame in list_frame:
                if isinstance(frame, DraggableWidget):
                    frame.setStyleSheet(frame.default_StyleSheet)
                    frame.selected = False
                    frame.all_save_event()

            self.selected_frames = []
        # 选择结束
        elif event.button() == Qt.LeftButton and self.selecting:
            self.selecting = False
            self.selected_frames = []
            list_frame = self.children()
            # 判断框选的方向
            if self.selection_start_pos.y() < event.pos().y():
                for frame in list_frame:
                    if isinstance(frame, DraggableWidget) and self.selection_rect.contains(frame.geometry()):
                        self.selected_frames.append(frame)
            elif self.selection_start_pos.y() > event.pos().y():
                for frame in list_frame:
                    if isinstance(frame, DraggableWidget) and self.selection_rect.intersects(frame.geometry()):
                        self.selected_frames.append(frame)
            else:
                pass
            # 将选择中的改变样式
            for frame in self.selected_frames:
                frame.setStyleSheet(frame.select_StyleSheet)
                frame.selected = True
            self.update()
        # 这个是为了选中后没点击选择的控件进行了重新选择
        else:
            list_frame = self.children()
            for frame in list_frame:
                if isinstance(frame, DraggableWidget):
                    frame.setStyleSheet(frame.default_StyleSheet)
                    frame.selected = False
            self.selected_frames = []

    def paintEvent(self, event):
        super().paintEvent(event)
        # 绘画选择框
        # todo 此处有异常问题待处理:选择框一直在控件后方，需要显示在最上层
        if self.selecting:
            self.raise_()
            painter = QPainter(self)
            pen = QPen(Qt.red)
            pen.setStyle(Qt.DashDotDotLine)
            pen.setWidth(2)
            painter.setPen(pen)
            painter.drawRect(self.selection_rect)


class ScrollingLabel(QLabel):
    def __init__(self, text='', timer_scrollLabel=Signal(), parent=None):
        super().__init__(text, parent)
        self.setStyleSheet("QLabel { background-color: transparent; }")
        # self.setFixedWidth(40)
        self.setToolTip(text)
        self.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        timer_scrollLabel.timeout.connect(self.scrollText)
        self.speed = 1
        self.offset = 0
        self.dir = 0
        self.text_width = self.fontMetrics().boundingRect(self.text()).width()

    def scrollText(self):
        if self.width() > self.text_width:
            pass
        else:
            # self.offset += self.speed
            # self.repaint()
            #
            # if self.offset >= self.text_width - self.width() + 5:
            #     self.offset = 0 - 5
            if self.dir == 0:
                self.offset += self.speed
                self.repaint()

                if self.offset >= self.text_width - self.width() + 5:
                    self.dir = 1
            elif self.dir == 1:
                self.offset -= self.speed
                self.repaint()

                if self.offset <= -5:
                    self.dir = 0

    def paintEvent(self, event):
        if self.width() > self.text_width:
            super().paintEvent(event)
        else:
            painter = QPainter(self)
            painter.drawText(-self.offset, 0, self.text_width, self.height(), Qt.AlignLeft | Qt.AlignVCenter, self.text())


class CustomTabWidget(QTabWidget):
    delete_self_signal = Signal(QFrame)

    def __init__(self,
                 parent=None,
                 grid_size=[1, 1],
                 config=None,
                 signal_table_info=Signal(),
                 delete_self_signal=Signal(),
                 signal_online_stateChanged=Signal(),
                 timer_scrollLabel=Signal(),
                 queue_logging=Queue(),
                 table_info=None,
                 ):
        super().__init__(parent)
        # 获取变量
        self.grid_size = grid_size
        self.config = config
        self.signal_table_info = signal_table_info
        self.signal_online_stateChanged = signal_online_stateChanged
        self.timer_scrollLabel = timer_scrollLabel
        # self.signal_online_stateChanged.connect(self.set_drag_enable)
        self.queue_logging = queue_logging
        self.table_info = table_info
        self.DraggableWidget_Object = DraggableWidget

        # 创建变量
        self.tab_list = []
        self.draggable_widgets = {}
        self.drag_enable = True

        # 初始化配置
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.showContextMenu)
        self.setElideMode(Qt.ElideNone)
        self.setMovable(True)
        self.setTabBarAutoHide(True)

        # 关联删除信号
        self.delete_widget = None
        self.delete_self_signal.connect(self.delay_delete)
        self.timer_delete_one_widget = QTimer()
        self.timer_delete_one_widget.timeout.connect(lambda: self.delete_one_widget(self.delete_widget))

    def add_draggableWidget(self, widget_type=2, addr=0, config=None, parent_name=None):
        try:
            if not self.drag_enable:
                return
            if parent_name is None:
                parent_name = self.tabText(self.currentIndex())
            if config is None:
                # 生成config信息
                config = {
                    'uniqueID': self.table_info['uniqueID'][addr],
                    'widget_type': widget_type,
                }
            else:
                addr = self.table_info['uniqueID'].index(config['uniqueID'])
                widget_type = config['widget_type']

            if str(addr) in list(self.draggable_widgets[parent_name].keys()):
                for widget in self.draggable_widgets[parent_name][str(addr)]:
                    if widget.config['widget_type'] == widget_type:
                        QMessageBox.information(self, "提示", "已经添加一个了", QMessageBox.Yes)
                        return

            # 获取名为parent_name的widget
            for i in range(self.count()):
                if self.tabText(i) == parent_name:
                    widget = self.widget(i).widget
                    break

            # 添加组件
            widget = DraggableWidget(parent=widget,
                                     grid_size=self.grid_size,
                                     config=config,
                                     signal_table_info=self.signal_table_info,
                                     delete_self_signal=self.delete_self_signal,
                                     signal_online_stateChanged=self.signal_online_stateChanged,
                                     timer_scrollLabel=self.timer_scrollLabel,
                                     table_info=self.table_info,
                                     queue_logging=self.queue_logging,
                                     addr=addr)

            # 将添加的dockwidget记录下来方便访问
            if str(addr) in self.draggable_widgets[parent_name]:
                self.draggable_widgets[parent_name][str(addr)].append(widget)
            else:
                self.draggable_widgets[parent_name][str(addr)] = [widget]

            # # 如果是添加的第一个就打开console界面
            # if len(self.draggable_widgets) == 1 and not self.isVisible():
            #     self.show()
            #     self.signal_operat.emit(6, 1, [type(self)])
            #     self.scroll_area.setSize([300, 300])
        except Exception as e:
            # my_logger.debug('自动屏蔽了一个已经修改名字的控件')
            self.queue_logging.put([1, 0, '自动屏蔽了一个已经修改名字的控件'])

    def refresh(self, addrs, values):
        for i in range(len(addrs)):
            if str(addrs[i]) in self.draggable_widgets[self.tabText(self.currentIndex())].keys():
                self.table_info['var_current'][addrs[i]] = values[i]
                for widget in self.draggable_widgets[self.tabText(self.currentIndex())][str(addrs[i])]:
                    widget.widget.refresh(values[i])
            else:
                pass

    def load_config(self):
        if self.config is not None:
            if 'tab_name' in self.config:
                for tab_name in self.config['tab_name']:
                    self.add_tab(tab_name)

                for parent_name in self.config['tab_name']:
                    for widget_config in self.config['widgets'][parent_name]:
                        self.add_draggableWidget(config=widget_config, parent_name=parent_name)

                for i in range(self.count()):
                    self.handling_overlap(self.widget(i).widget)
            else:
                # 如果一个都没有就添加第一个
                self.add_tab('New Tab')
                for widget_config in self.config['widgets']:
                    self.add_draggableWidget(config=widget_config, parent_name='New Tab')

            if 'tab_tip_list' in self.config:
                for i in range(self.count()):
                    self.setTabToolTip(i, self.config['tab_tip_list'][i])

            if 'curr_tab_name' in self.config:
                for i in range(self.count()):
                    if self.tabText(i) == self.config['curr_tab_name']:
                        self.setCurrentIndex(i)
                        break

        else:
            self.add_tab('New Tab')
        if not self.tab_list:
            self.add_tab('New Tab')

    def sort_by_pos(self, button):
        """ 负责给排序传递参数 """
        return button.config['pos'][0], button.config['pos'][1]

    def handling_overlap(self, widget):
        """ 解决因添加按钮个数导致的覆盖问题 """
        # 根据行和列重新将控件list排序
        temp_list = sorted(widget.children(), key=self.sort_by_pos)
        # 将重叠的控件向又依次移动直到不重叠
        for child1 in temp_list:
            rect = child1.geometry()
            for child2 in temp_list:
                if isinstance(child2, DraggableWidget) and child2 is not child1:
                    if rect.intersects(child2.geometry()):
                        x, y = child2.geometry().x(), child2.geometry().y()
                        while rect.intersects(child2.geometry()):
                            x += self.grid_size[0]
                            child2.move(QPoint(x, y))
                        child2.config['pos'] = [x, y]


    def get_config(self):
        curr_tab_name = ''
        tab_list = []
        tab_tip_list = []
        widgets_list = {}
        curr_tab_name = self.tabText(self.currentIndex())
        for i in range(self.count()):
            tab_list.append(self.tabText(i))
            tab_tip_list.append(self.tabToolTip(i))
            widgets_list[self.tabText(i)] = []
            for widget in self.widget(i).findChildren(
                    self.DraggableWidget_Object):
                widgets_list[self.tabText(i)].append(widget.config)
        return curr_tab_name, tab_list, tab_tip_list, widgets_list

    def showContextMenu(self, pos):
        if not self.drag_enable:
            return
        index = self.tabBar().tabAt(pos)
        if index != -1:
            menu = QMenu(self)

            # 改名
            rename_action = QAction("改名", self)
            rename_action.triggered.connect(lambda: self.renameTab(index))
            menu.addAction(rename_action)

            # 删除标签页
            delete_action = QAction("删除标签页", self)
            delete_action.triggered.connect(lambda: self.deleteTab(index))
            menu.addAction(delete_action)

            # 新建标签页
            new_action = QAction("新建标签页", self)
            new_action.triggered.connect(self.createNewTab)
            menu.addAction(new_action)

            # 添加描述
            tip_action = QAction("添加或修改描述", self)
            tip_action.triggered.connect(lambda: self.setTips(index))
            menu.addAction(tip_action)

            menu.exec(self.mapToGlobal(pos))
        else:
            if len(self.draggable_widgets) > 0:
                child = self.childAt(pos)
                # print(child)
                action = None
                # print(child)
                if child is None or isinstance(child, My_Widget):
                    action = QAction("Delete ALL", self)
                    action.triggered.connect(lambda: self.delete_all_widgets(self.currentWidget(), True))
                else:
                    widget_to_delete = None
                    if isinstance(child, QLabel) and isinstance(
                            child.parent(), self.DraggableWidget_Object):
                        widget_to_delete = child.parent()
                    elif isinstance(child, self.DraggableWidget_Object):
                        widget_to_delete = child
                    if widget_to_delete:
                        action = QAction("Delete", self)
                        action.triggered.connect(
                            lambda: self.delete_one_widget(widget_to_delete))
                if action:
                    menu = QMenu(self)
                    menu.addAction(action)
                    menu.exec(self.mapToGlobal(pos))

    def set_drag_enable(self, flag):
        self.drag_enable = not flag

    def resize_widget(self):
        """
            重写DockerWidget的resizeEvent函数
            调整DockerWidget的大小后获取scroll_area的大小以及计算content_widget的最佳大小
            自动调整content_widget大小
        """
        # self.findChildren(QAbstractButton, "qt_dockwidget_closebutton")
        # self.findChildren(QAbstractButton, "qt_dockwidget_floatbutton")
        # 计算最佳大小
        # 找到最右下角的控件的右下角端点坐标,即刚好显示全部控件的最小content_widget尺寸
        tab_widgets = []
        for index in range(self.count()):
            widget = self.widget(index).widget
            tab_widgets.append(widget)

        for tab_widget in tab_widgets:

            x0, y0 = 0, 0
            widgets = tab_widget.findChildren(DraggableWidget)
            for widget in widgets:
                coordinate = widget.geometry().bottomRight()
                x_tmp, y_tmp = coordinate.x(), coordinate.y()
                if x0 < x_tmp:
                    x0 = x_tmp
                if y0 < y_tmp:
                    y0 = y_tmp
            # 获取scroll_area的大小
            scroll_area_size = self.parent().size()

            x = max(scroll_area_size.width(), x0)
            y = max(scroll_area_size.height(), y0)

            tab_widget.setFixedSize(x, y)

    def delete_all_widgets(self, widgets, MSG):
        """ 清除所有控件 """
        if MSG:
            reply = QMessageBox.question(self, '删除', '确认要删除所有控件吗？', QMessageBox.Yes | QMessageBox.Cancel)
            if reply == QMessageBox.Yes:
                for widget in widgets.findChildren(
                        self.DraggableWidget_Object):
                    widget.delete_myself()
                self.draggable_widgets[self.tabText(self.indexOf(widgets))] = {}
            else:
                pass
        else:
            for widget in widgets.findChildren(
                    self.DraggableWidget_Object):
                widget.delete_myself()
            self.draggable_widgets[self.tabText(self.indexOf(widgets))] = {}

    def delay_delete(self, widget):
        self.delete_widget = widget
        self.timer_delete_one_widget.setSingleShot(True)
        self.timer_delete_one_widget.start(1)

    def delete_one_widget(self, widget):
        """删除指定控件"""
        widget.delete_myself()
        self.draggable_widgets[self.tabText(self.currentIndex())][str(widget.addr)].remove(widget)

    def createNewTab(self):
        default = 'New Tab'
        while default in self.tab_list:
            if default[-1].isdigit():
                default = default[:-1] + str(int(default[-1]) + 1)
            else:
                default = default + str(1)

        new_text, ok = QInputDialog.getText(self, "新建", "请输入新的标签名", text=default)
        if ok:
            if new_text in self.tab_list:
                QMessageBox.information(self, '提示', '名字重复请重试!', QMessageBox.Yes)
            else:
                self.add_tab(new_text)
        else:
            pass

        # self.add_tab(new_text)
        # new_tab_index = self.addTab(My_Widget(), new_text)
        # self.setCurrentIndex(new_tab_index)

    def renameTab(self, index):
        current_text = self.tabText(index)
        new_text, ok = QInputDialog.getText(self, "改名", "请输入新的标签名", text=current_text)
        if ok:
            if new_text == current_text:
                pass
            elif new_text in self.tab_list:
                QMessageBox.information(self, '提示', '已经有了同名Tab存在\n请重试!', QMessageBox.Yes)
                self.renameTab(index)
            else:
                value_temp = self.draggable_widgets[self.tabText(index)]
                del self.draggable_widgets[self.tabText(index)]
                self.draggable_widgets[new_text] = value_temp
                self.tab_list.remove(self.tabText(index))
                self.tab_list.append(new_text)
                self.setTabText(index, new_text)
        else:
            pass

    def deleteTab(self, index):
        if len(self.tab_list) == 1:
            QMessageBox.information(self, '提示', '只剩下最后一个Tab页面了\n无法进行删除操作!', QMessageBox.Yes)
            return
        if self.draggable_widgets[self.tabText(index)]:
            reply = QMessageBox.information(self, '删除', '是否要删除该页并同时清除该页所有控件\n此动作无法撤销 请注意!!!', QMessageBox.Yes | QMessageBox.Cancel)
            if reply == QMessageBox.Yes:
                self.delete_all_widgets(self.widget(index), False)
                del self.draggable_widgets[self.tabText(index)]
                self.tab_list.remove(self.tabText(index))
                self.removeTab(index)
            else:
                pass
        else:
            del self.draggable_widgets[self.tabText(index)]
            self.tab_list.remove(self.tabText(index))
            self.removeTab(index)

    def setTips(self, index):
        old_tips = self.tabToolTip(index)
        new_tips, ok = QInputDialog.getMultiLineText(self, '提示', '请输入新的提示内容', text=old_tips)
        if ok:
            if new_tips == old_tips:
                pass
            else:
                self.setTabToolTip(index, new_tips)
        else:
            pass

    def add_tab(self, text_name):

        # 添加scroll area 用于自动设置滚动条
        scroll_area = My_ScrollArea()
        # setWidget(scroll_area)
        scroll_area.setWidgetResizable(True)
        scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        scroll_area.setStyleSheet(
            "QScrollBar:vertical {width: 15px;height: 15px;}")

        scroll_area.widget = My_Widget(scroll_area, self.signal_online_stateChanged)
        # scroll_area.widget.setFixedSize(1000, 1000)
        new_tab_index = self.addTab(scroll_area, text_name)
        scroll_area.setWidget(scroll_area.widget)
        self.tab_list.append(text_name)
        self.draggable_widgets[text_name] = {}
        self.setCurrentIndex(new_tab_index)

